-
Notifications
You must be signed in to change notification settings - Fork 23
[EVM] Support for spilling constants to memory #885
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
|
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #885 +/- ##
=======================================
Coverage 30.03% 30.04%
=======================================
Files 2430 2431 +1
Lines 704105 704196 +91
Branches 176501 176520 +19
=======================================
+ Hits 211480 211571 +91
- Misses 448676 448679 +3
+ Partials 43949 43946 -3 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
f14e6fc to
293b9ef
Compare
|
📊 Excel Report Available Benchmarks measured for:
|
293b9ef to
fc6d80a
Compare
|
✅ With the latest revision this PR passed the C/C++ code formatter. |
2dd2ebb to
c4fb743
Compare
c4fb743 to
a5d2fa1
Compare
a5d2fa1 to
91de0ee
Compare
|
📊 evm compiler-tester excel report Benchmarks measured for:
|
|
|
5a40615 to
7098b6d
Compare
9c8da3c to
3a2fa00
Compare
…pipeline This allows other passes to modify or adjust frame indexes before finalization.
The constant spilling mechanism is divided between two components:
- ConstantUnfolder
Determines which constants are profitable to spill. For these constants,
it emits codegen-only 'IMM_RELOAD Imm' instructions.
- ConstantSpiller
Inserts spills at the beginning of the entry machine function and replaces
IMM_RELOAD instructions with the actual reloads. It also calculates the
required size of the constants’ spill area in the heap. ConstantSpiller
is called from EVMFinalizeStackFrames so that the actual offsets to the
spill area can be computed.
3a2fa00 to
78341c6
Compare
akiramenai
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Needs polishing
| // spilling after stackification. This helps reduce compilation time, | ||
| // since otherwise we would need to compile roughly twice as many | ||
| // contracts. | ||
| CanSpill = any_of(MFs, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maintainability: Can we use early exit here and emptiness of ImmToUseCount in isSpillEligible?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeap, thank you.
| // | ||
| //===----------------------------------------------------------------------===// | ||
| // | ||
| // This file identifies IMM_RELOAD instructions representing spilled constants |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why IMM_RELOAD if term constant is also use and constant is the correct term?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed to CONSTANT_RELOAD.
| MachineBasicBlock::iterator InsertBefore, | ||
| const EVMInstrInfo *TII, const APInt &Imm, | ||
| LLVMContext &Ctx, const DebugLoc &DL) { | ||
| unsigned Opc = EVM::getPUSHOpcode(Imm); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maintainability: Similar logic already exists in EVMConstantUnfolding.cpp and probably other EVM::getPUSHOpcode call sites. Can we unify it?
| LLVMContext &Ctx = EntryMF.getFunction().getContext(); | ||
| const EVMInstrInfo *TII = EntryMF.getSubtarget<EVMSubtarget>().getInstrInfo(); | ||
|
|
||
| DenseMap<APInt, uint64_t> ConstantToSpillOffset; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maintainability: Spill offset == Num of const in ConstantToUseCount map * 32. Do we need a separate map for it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's convenient to have a map with final offsets because, as we refer to this info twice. The second time if when we walk over reloads.
| SpillOffset += SpillSlotSize; | ||
| } | ||
|
|
||
| // Emit constant stores in prologue of the entry function. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can probably elaborate this with a call graph and CFG analysis to make the pass more practical. Can we create a follow-up ticket + TODO?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right, there could be several strategies. For example, we could compute the frequency of constants and perform spills at the machine function (MF) level.
However, in optimized builds (e.g., with -O3), many functions are inlined into the entry function, so inserting the constant-spilling code at the beginning of __entry seems like a reasonable approach.
| << ", at offset: " << Offset << '\n'; | ||
| }); | ||
|
|
||
| BuildMI(SpillMBB, SpillMBB.begin(), DebugLoc(), TII->get(EVM::MSTORE_S)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maintainability: Reverse order complicates comprehension.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, fixed.
| cl::init(0), | ||
| cl::desc("EVM metadata size")); | ||
|
|
||
| static cl::opt<unsigned> ConstantSpillThreshold( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you explain why we need to couple spilling and materialization logic? How one affects the other?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've replaced ConstantSpillThreshold with ConstantReloadThreshold, or you mean why this options is in the ConstantUnfolding file?
vladimirradosavljevic
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can see some performance degradations with this patch, and some nice size improvements, so should we only enable this for size optimizations?
| addPass(createEVMOptimizeLiveIntervals()); | ||
| addPass(createEVMSingleUseExpression()); | ||
| addPass(createEVMBPStackification()); | ||
| addPass(&StackSlotColoringID); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You don't need to move StackSlotColoringID, as this optimization works only with LiveIntervals that are only added in the EVMBPStackification.
Code Review Checklist
Purpose
Ticket Number
Requirements
Implementation
Logic Errors and Bugs
code does not behave as intended?
that could break the code?
Error Handling and Logging
be added or removed?
written in a way that allows for easy
debugging?
Maintainability
Dependencies
Security
Performance
system performance?
performance of the code significantly?
Testing and Testability
that should be tested in addition?
Readability
smaller methods?
different function, method or variable names?
file/folder/package?
restructured to have a more intuitive control
flow?
better?
understandable?
Documentation
Best Practices
Experts' Opinion
expert or a usability expert, should look over
the code before it can be accepted?